package com.ly.recommend;

import com.ly.entity.Score;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * @author : 黑渊白花
 * @ClassName CoreMath
 * @date : 2025/5/10 21:16
 * @Description
 */

public class CoreMath {

    //https://blog.csdn.net/weixin_43895362/article/details/135939869

    /**
     * 计算相关系数并排序
     * @param key
     * @param map
     * @return Map<Integer,Double>
     */
    public static Map<Integer,Double> computeNeighbor(Integer key, Map<Integer,List<Score>>  map,int type) {
        Map<Integer,Double> distMap = new TreeMap<>();
        List<Score> userItems=map.get(key);
        map.forEach((k,v)->{
            //排除此用户
            if(!k.equals(key)){
                //关系系数
                double coefficient = relateDist(v,userItems,type);
                //关系距离
                // double distance=Math.abs(coefficient);
                distMap.put(k,coefficient);
            }
        });
        return distMap;
    }


    /**
     * 计算两个序列间的相关系数
     *
     * @param xList
     * @param yList
     * @param type 类型0基于用户推荐 1基于物品推荐
     * @return double
     */
    private static double relateDist(List<Score> xList, List<Score> yList, int type) {
        //原本是double
        List<Double> xs= new ArrayList<>();
        List<Double> ys= new ArrayList<>();
        xList.forEach(x->{
            yList.forEach(y->{
                if(type==0){
                    if(x.getActId().equals(y.getActId())){
                        xs.add(x.getScore());
                        ys.add(y.getScore());
                    }
                }else{
                    if(x.getStuId().equals(y.getStuId())){
                        xs.add(x.getScore());
                        ys.add(y.getScore());
                    }
                }
            });
        });
        return getRelate(xs,ys);
    }

    /**
     * 方法描述: 皮尔森（pearson）相关系数计算
     *
     * @param xs x集合
     * @param ys y集合
     */
    public static double getRelate(List<Double> xs, List<Double> ys){
        int n=xs.size();
        //至少有两个元素
        if (n<2) {
            return 0D;
        }
        double Ex= xs.stream().mapToDouble(x->x).sum();
        double Ey=ys.stream().mapToDouble(y->y).sum();
        double Ex2=xs.stream().mapToDouble(x->Math.pow(x,2)).sum();
        double Ey2=ys.stream().mapToDouble(y->Math.pow(y,2)).sum();
        double Exy= IntStream.range(0,n).mapToDouble(i->xs.get(i)*ys.get(i)).sum();
        double numerator=Exy-Ex*Ey/n;
        double denominator=Math.sqrt((Ex2-Math.pow(Ex,2)/n)*(Ey2-Math.pow(Ey,2)/n));
        if (denominator==0) {
            return 0D;
        }
        return numerator/denominator;
    }

    //物品：type=1、Score::getActId
    public static List<Integer> itemCFRecommend(int actId,List<Score> list){
        //获取用户的所有评分
        Map<Integer, List<Score>>  itemMap=list.stream().collect(Collectors.groupingBy(Score::getActId));
        //获取其他物品与当前物品的关系值
        Map<Integer, Double> itemDisMap = computeNeighbor(actId, itemMap, 1);
        //获取关系最近物品
        double maxValue= Collections.max(itemDisMap.values());
        return itemDisMap.entrySet().stream()
                .filter(e->e.getValue()==maxValue)
                .map(Map.Entry::getKey).collect(Collectors.toList());
    }

    //用户：type=0、Score::getStuId
    public static List<Integer> userCFRecommend(int stuId, List<Score> list) {
        // 获取物品的所有评分
        Map<Integer, List<Score>> userMap = list.stream().collect(Collectors.groupingBy(Score::getStuId));
        // 获取其他用户与当前用户的关系值
        Map<Integer, Double> userDisMap = computeNeighbor(stuId, userMap, 0);
        // 获取关系最近用户
        double maxValue = Collections.max(userDisMap.values());
        return userDisMap.entrySet().stream()
                .filter(e -> e.getValue() == maxValue)
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());
    }



}
